home *** CD-ROM | disk | FTP | other *** search
- /*
- * main.c --
- *
- * Main program for Tcl shells and other Tcl-based applications.
- *
- * Copyright (c) 1988-1993 The Regents of the University of California.
- * All rights reserved.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
- * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
- * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- */
-
- #ifndef lint
- static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclMain.c,v 1.10 93/09/17 17:32:47 ouster Exp $ SPRITE (Berkeley)";
- #endif
-
- #include "tclInt.h"
- #include "tclUnix.h"
-
- #ifdef THINK_C
- # include <console.h>
- #endif
-
- static Tcl_Interp *interp; /* Interpreter for application. */
- static Tcl_DString command; /* Used to buffer incomplete commands being
- * read from stdin. */
- char *tcl_RcFileName = NULL; /* Name of a user-specific startup script
- * to source if the application is being run
- * interactively (e.g. "~/.tclshrc"). Set
- * by Tcl_AppInit. NULL means don't source
- * anything ever. */
- #ifdef TCL_MEM_DEBUG
- static char dumpFile[100]; /* Records where to dump memory allocation
- * information. */
- static int quitFlag = 0; /* 1 means the "checkmem" command was
- * invoked, so the application should quit
- * and dump memory allocation information. */
- #endif
-
- /*
- * Forward references for procedures defined later in this file:
- */
-
- static int CheckmemCmd _ANSI_ARGS_((ClientData clientData,
- Tcl_Interp *interp, int argc, char *argv[]));
-
- /*
- *----------------------------------------------------------------------
- *
- * main --
- *
- * This is the main program for a Tcl-based shell that reads
- * Tcl commands from standard input.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Can be almost arbitrary, depending on what the Tcl commands do.
- *
- *----------------------------------------------------------------------
- */
-
- #ifdef macintosh
-
- char **environ = NULL;
-
- #endif
-
-
- int
- #ifdef MPW
-
- main(argc, argv, envp)
- int argc; /* Number of arguments. */
- char **argv; /* Array of argument strings. */
- char **envp; /* Array of environment strings. */
-
- #else
-
- main(argc, argv)
- int argc; /* Number of arguments. */
- char **argv; /* Array of argument strings. */
-
- #endif
- {
- char buffer[1000], *cmd, *args, *fileName;
- int code, gotPartial, tty;
- int exitCode = 0;
-
- #ifdef MPW
- char prompt_prefix[128];
- #endif
-
- #ifdef THINK_C
- console_options.pause_atexit = 0;
- console_options.title = "\pTcl Shell";
- printf("Macintosh Tcl Shell. Tcl version 7.0, with extensions.\n");
- #endif
-
- #ifdef THINK_C
- {
- int i;
- char buffer[1024];
-
- environ = (char **) ckalloc( 5 * sizeof(char *) );
- if (environ == NULL)
- {
- fprintf(stderr, "could not malloc environ");
- exit(1);
- }
-
- i = 0;
-
- #ifdef TCL_LIBRARY
- sprintf(buffer, "TCL_LIBRARY=%s", TCL_LIBRARY);
- environ[i] = ckalloc( strlen(buffer) + 1 );
- strcpy(environ[i++], buffer);
- #endif
-
- #ifdef THINK_C
- environ[i++] = "THINK_VERSION=1";
- #endif
-
- environ[i] = NULL;
- }
- #endif
-
- #ifdef MPW
- {
- int i;
- char *ptr;
-
- for ( i = 0 ; envp[i] != NULL ; i++ )
- ;
-
- environ = (char **) ckalloc( (i + 2) * sizeof(char *) );
- if (environ == NULL)
- {
- fprintf(stderr, "could not malloc environ");
- exit(1);
- }
-
- for ( i = 0 ; envp[i] != NULL ; i++ )
- {
- for ( ptr = envp[i] ; *ptr++ ; )
- ;
-
- environ[i] = ckalloc( strlen(envp[i]) + strlen(ptr) + 2 );
-
- strcpy(environ[i], envp[i]);
- strcat(environ[i], "=");
- strcat(environ[i], ptr);
- }
-
- environ[i] = NULL;
- }
- #endif
-
- interp = Tcl_CreateInterp();
-
- #ifdef TCL_MEM_DEBUG
- Tcl_InitMemory(interp);
- Tcl_CreateCommand(interp, "checkmem", CheckmemCmd, (ClientData) 0,
- (Tcl_CmdDeleteProc *) NULL);
- #endif
-
- /*
- * Make command-line arguments available in the Tcl variables "argc"
- * and "argv". If the first argument doesn't start with a "-" then
- * strip it off and use it as the name of a script file to process.
- */
-
- fileName = NULL;
- if ((argc > 1) && (argv[1][0] != '-'))
- {
- fileName = argv[1];
- argc--;
- argv++;
- }
- args = Tcl_Merge(argc-1, argv+1);
- Tcl_SetVar(interp, "argv", args, TCL_GLOBAL_ONLY);
- ckfree(args);
- sprintf(buffer, "%d", argc-1);
- Tcl_SetVar(interp, "argc", buffer, TCL_GLOBAL_ONLY);
- Tcl_SetVar(interp, "argv0", (fileName != NULL) ? fileName : argv[0],
- TCL_GLOBAL_ONLY);
-
- /*
- * Set the "tcl_interactive" variable.
- */
-
- tty = isatty(0);
- Tcl_SetVar(interp, "tcl_interactive",
- ((fileName == NULL) && tty) ? "1" : "0", TCL_GLOBAL_ONLY);
-
- /*
- * Invoke application-specific initialization.
- */
-
- if (Tcl_AppInit(interp) != TCL_OK)
- {
- fprintf(stderr, "Tcl_AppInit failed: %s\n", interp->result);
- }
-
- /*
- * If a script file was specified then just source that file
- * and quit.
- */
-
- if (fileName != NULL) {
- code = Tcl_EvalFile(interp, fileName);
- if (code != TCL_OK) {
- fprintf(stderr, "%s\n", interp->result);
- exitCode = 1;
- }
- goto done;
- }
-
- /*
- * We're running interactively. Source a user-specific startup
- * file if Tcl_AppInit specified one and if the file exists.
- */
-
- if (tcl_RcFileName != NULL) {
- Tcl_DString buffer;
- char *fullName;
-
- fullName = Tcl_TildeSubst(interp, tcl_RcFileName, &buffer);
- if (fullName == NULL) {
- fprintf(stderr, "%s\n", interp->result);
- } else {
- if (access(fullName, R_OK) == 0) {
- code = Tcl_EvalFile(interp, fullName);
- if (code != TCL_OK) {
- fprintf(stderr, "%s\n", interp->result);
- }
- }
- }
- Tcl_DStringFree(&buffer);
- }
-
- /*
- * Process commands from stdin until there's an end-of-file.
- */
-
- gotPartial = 0;
- Tcl_DStringInit(&command);
- while (1)
- {
- clearerr(stdin);
- if (tty)
- {
- char *promptCmd;
-
- promptCmd = Tcl_GetVar( interp,
- (gotPartial ? "tcl_prompt2" : "tcl_prompt1"),
- TCL_GLOBAL_ONLY );
- if (promptCmd == NULL)
- {
- defaultPrompt:
- if (! gotPartial)
- {
- fputs("% ", stdout);
- #ifdef MPW
- strcpy(prompt_prefix, "% ");
- #endif
- }
- }
- else
- {
- code = Tcl_Eval(interp, promptCmd);
- if (code != TCL_OK)
- {
- fprintf(stderr, "%s\n", interp->result);
- Tcl_AddErrorInfo(interp,
- "\n (script that generates prompt)");
- goto defaultPrompt;
- }
- #ifdef MPW
- else
- {
- strcpy(prompt_prefix, interp->result);
- }
- #endif
- }
- fflush(stdout);
- }
-
- if (fgets(buffer, 1000, stdin) == NULL)
- {
- if (ferror(stdin))
- {
- if (errno == EINTR)
- {
- if (tcl_AsyncReady)
- {
- (void) Tcl_AsyncInvoke((Tcl_Interp *) NULL, 0);
- }
- clearerr(stdin);
- }
- else
- {
- goto done;
- }
- }
- else
- {
- if (!gotPartial)
- {
- goto done;
- }
- }
- buffer[0] = 0;
- }
-
- #ifdef MPW
- {
- int plen, blen;
-
- blen = strlen(buffer);
- plen = strlen(prompt_prefix);
-
- if ( blen > plen && strncmp( buffer, prompt_prefix, plen ) == 0 )
- {
- memmove( buffer, &buffer[ plen ], ( blen - plen ) );
- buffer[ blen - plen ] = '\0';
- }
- }
- #endif
-
- cmd = Tcl_DStringAppend(&command, buffer, -1);
- if ((buffer[0] != 0) && !Tcl_CommandComplete(cmd))
- {
- gotPartial = 1;
- continue;
- }
-
- gotPartial = 0;
- code = Tcl_RecordAndEval(interp, cmd, 0);
- Tcl_DStringFree(&command);
- if (code != TCL_OK)
- {
- fprintf(stderr, "%s\n", interp->result);
- }
- else if (tty && (*interp->result != 0))
- {
- printf("%s\n", interp->result);
- }
- #ifdef TCL_MEM_DEBUG
- if (quitFlag)
- {
- Tcl_DeleteInterp(interp);
- Tcl_DumpActiveMemory(dumpFile);
- exit(0);
- }
- #endif
- }
-
- /*
- * Rather than calling exit, invoke the "exit" command so that
- * users can replace "exit" with some other command to do additional
- * cleanup on exit. The Tcl_Eval call should never return.
- */
-
- done:
- sprintf(buffer, "exit %d", exitCode);
- Tcl_Eval(interp, buffer);
- return 1;
- }
-
- /*
- *----------------------------------------------------------------------
- *
- * CheckmemCmd --
- *
- * This is the command procedure for the "checkmem" command, which
- * causes the application to exit after printing information about
- * memory usage to the file passed to this command as its first
- * argument.
- *
- * Results:
- * Returns a standard Tcl completion code.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- #ifdef TCL_MEM_DEBUG
-
- /* ARGSUSED */
- static int
- CheckmemCmd(clientData, interp, argc, argv)
- ClientData clientData; /* Not used. */
- Tcl_Interp *interp; /* Interpreter for evaluation. */
- int argc; /* Number of arguments. */
- char *argv[]; /* String values of arguments. */
- {
- if (argc != 2) {
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
- " fileName\"", (char *) NULL);
- return TCL_ERROR;
- }
- strcpy(dumpFile, argv[1]);
- quitFlag = 1;
- return TCL_OK;
- }
- #endif
-